import Foundation
import CoreLocation
import Combine

struct LocationInfo: Equatable {
    var city: String
}

extension CLLocationCoordinate2D: @retroactive Equatable {
    public static func == (lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool {
        lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude
    }
}

enum LocationError: BaseError {
    
    case noAuth
    case cityFail
    case fail
    
    var message: String {
        switch self {
        case .noAuth:
            return "定位权限被拒绝或受限，请在设置中开启"
        case .cityFail:
            return "获取城市信息失败"
        case .fail:
            return "定位失败"
        }
    }
    
    
}

/// 管理定位与城市信息的服务类
@Observable final class LocationService: NSObject {
    private let locationManager = CLLocationManager()
    
    var error: LocationError?
    var locationInfo: LocationInfo = LocationInfo(city: "定位中...")
    var locationCoordinate: CLLocationCoordinate2D?
    
    var cityName: String {
        locationInfo.city
    }
    
    var latitude: String? {
        guard let lat = locationCoordinate?.latitude else {
            return nil
        }
        return String(lat)
    }
    
    var longitude: String? {
        guard let lon = locationCoordinate?.longitude else {
            return nil
        }
        return String(lon)
    }
    
    override init() {
        super.init()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
    }

    /// 请求一次位置
    func requestLocation() {
        let status = locationManager.authorizationStatus
        switch status {
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .authorizedWhenInUse, .authorizedAlways:
            locationManager.requestLocation()
        case .denied, .restricted:
            Log.error("无权使用定位，没有开启")
            error = .noAuth
            locationInfo.city = "无定位权限"
        default:
            break
        }
    }

    /// 开始持续监听位置（可选功能）
//    func startUpdating() {
//        locationManager.startUpdatingLocation()
//    }

//    func stopUpdating() {
//        locationManager.stopUpdatingLocation()
//    }

    /// 反向地理编码，获取城市名
    private func fetchCityName(from coordinate: CLLocationCoordinate2D) {
        let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
        let geocoder = CLGeocoder()
        geocoder.reverseGeocodeLocation(location) { placemarks, error in
            if let error = error {
                DispatchQueue.main.async {
                    Log.error("获取城市信息失败：\(error.localizedDescription)")
                    self.error = .cityFail
                    self.locationInfo.city = "定位失败"
                }
                return
            }

            if let placemark = placemarks?.first {
                DispatchQueue.main.async {
                    self.locationInfo.city = placemark.locality ?? "未知城市"
                    Log.debug("定位的城市是\(self.locationInfo.city)")
                }
            }
        }
    }
}

extension LocationService: CLLocationManagerDelegate {
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let latest = locations.last {
            let coord = latest.coordinate
            DispatchQueue.main.async {
                Log.debug("定位坐标是\(coord.latitude)_\(coord.longitude)")
                self.locationCoordinate = coord
                self.error = nil
            }
            fetchCityName(from: coord)
        }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        DispatchQueue.main.async {
            Log.error("定位失败：\(error.localizedDescription)")
            self.error = .fail
            self.locationInfo = LocationInfo(city: "定位失败")
        }
    }

    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        requestLocation() // 授权改变时重新请求位置
    }
}

